#include <sys/socket.h>
#include <sys/epoll.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

#include <iostream>
#include <string>

#include "../ConnectMsg.h"
#include "../unity.h"
#include "../LogFile.h"
#include "Buffer.h"
#include "ServerProcess.h"

using std::cout;
using std::endl;
using std::string;


#ifdef SERVER_SHOW_LOG
	#include <sstream>
	#define OPERATE_TIME_LOG(op,file,msg) \
	{\
		long begin = getTime();\
		op;\
		long end = getTime();\
		std::ostringstream ostr;\
		ostr << msg << " spend time:" << end-begin << " us";\
		file.write(ostr.str());\
	}
#else
	#define OPERATE_TIME_LOG(op,file,msg) {op;}
#endif

const int MAXFDS = 5000;

int createListenSocket(int port)
{
	int listenfd = socket(AF_INET, SOCK_STREAM, 0);

	if (listenfd < 0)
	{
		errorExit("Create listen socket failed.");
	}

	int flag = 1;
	int flen = sizeof(flag);

	// 防止服务器程序因为TIME_WAIT导致的重启绑定失败
	if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR,
				(const void*)&flag, flen) == -1)
	{
		errorLog("setsockopt SO_REUSEADDR failed!");
	}

	if (setNoBlocking(listenfd) < 0)
	{
		errorLog("set listen fd no blocking failed!");
	}

	sockaddr_in servaddr;
	memset(&servaddr, 0, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(port);
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);


	if ( bind(listenfd, (sockaddr *) &servaddr, sizeof(servaddr)) == -1) 
	{	
		errorExit("bind faieled");
	}

	if ( listen(listenfd, 1024) == -1 )
	{
		errorExit("listen failed");
	}

	return listenfd;
}

int forkProcess(int processNum)
{
	int pid = -1;
	for (int i=0; i < processNum; ++i)
	{
		if (pid != 0)
		{
			pid = fork();
		}
		else
		{
			return pid;
		}
	}
	return pid;
}

void test()
{
	cout << 123 << endl;
}

int main(int argc, char** argv)
{
	LogFile file;
	OPERATE_TIME_LOG(test(),file,"test");
	return 0;
	int listenfd = createListenSocket(19877);

	const int PROCESS_NUM = 4;
	const int EVENT_NUM = 5000;
	int pid = forkProcess(PROCESS_NUM);

	if (pid == 0)
	{
		int i, connfd, sockfd, epfd, nfds;
		ssize_t n;
		socklen_t clilen;
		sockaddr_in cliaddr;

		epoll_event ev, events[EVENT_NUM];
		if ((epfd = epoll_create(8192)) == -1)
		{
			errorExit("epoll create failed.");
		}

		ev.data.fd = listenfd;
		ev.events = EPOLLIN|EPOLLET;
		epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &ev);

		const int BUF_LEN = 1024;
		unsigned char buffer[BUF_LEN];
		Buffer processBuffer(256);

		// 创建解析类
		ServerProcess servProc("test");

		for (;;)
		{
			nfds = epoll_wait(epfd, events, EVENT_NUM, 500);

			for (i=0; i<nfds; ++i)
			{
				if(events[i].events & (EPOLLERR | EPOLLHUP))
				{
					close(events[i].data.fd);
					events[i].data.fd = -1;
				}
				else if (events[i].data.fd == listenfd)
				{
					do
					{
						clilen = sizeof(cliaddr);
						if ((connfd = accept(listenfd, (sockaddr *)&cliaddr,
										&clilen)) == -1)
						{
							if (errno == EAGAIN)
								break;
							errorLog("accept failed");
							continue;
						}
						setNoBlocking(connfd);

						servProc.Init(connfd);

						ev.data.fd = connfd;
						ev.events = EPOLLIN | EPOLLET;
						epoll_ctl(epfd, EPOLL_CTL_ADD, connfd, &ev);
					}
					while(connfd > 0);
				}
				else if (events[i].events & EPOLLIN)
				{
					bool isClosed = false;
					if ((sockfd = events[i].data.fd) < 0)
						continue;
					ssize_t reciveSize;
					while ( (reciveSize = read(sockfd, buffer, BUF_LEN)) > 0 ||
							(reciveSize < 0 && errno == EINTR) )
					{
						buffer[0] = servProc.Recive(sockfd, buffer, reciveSize);

						processBuffer.Empty();
						int processSize =
						   	servProc.GetPack(sockfd, processBuffer);
						while (processSize > 0)
						{
							buffer[0] = 
								servProc.Process(processBuffer.GetBuffer(),
										processSize);
							processBuffer.Empty();
							// 发送
							int writeSize = write(sockfd, buffer, 1);
							if (writeSize < 0)
							{
								errorLog("write error");
							}
							else if (writeSize == 0)
							{
								close(events[i].data.fd);
								events[i].data.fd = -1;
								isClosed = true;
								break;
							}
							processSize = 
								servProc.GetPack(sockfd, processBuffer);
						}
						if (reciveSize < BUF_LEN)
						{
							break;
						}
					}

					if (isClosed)
					{
						break;
					}

					if (reciveSize == 0)
					{
						close(events[i].data.fd);
						events[i].data.fd = -1;
					}
					else if (reciveSize < 0 && errno != EAGAIN)
					{
						close(events[i].data.fd);
						events[i].data.fd = -1;
						errorLog("read error");
					}
				} // end else if epollin
			} // end loop epoll_wait
		} // end loop for
	} // end if pid
	else
	{
		for (int i=0; i < PROCESS_NUM; ++i)
		{
			wait(NULL);
		}
	}
}
